import logging
from abc import ABC, abstractmethod
from typing import Any, Callable, Dict, List, Optional, Tuple, Type

from gpt.model.adapter.llm_adapter import LLMModelAdapter


class AdapterEntry:
    """The entry of model adapter"""

    def __init__(
            self,
            model_adapter: LLMModelAdapter,
            match_funcs: List[Callable[[str, str, str], bool]] = None,
    ):
        self.model_adapter = model_adapter
        self.match_funcs = match_funcs or []


model_adapters: List[AdapterEntry] = []


def register_model_adapter(
        model_adapter_cls: Type[LLMModelAdapter],
        match_funcs: List[Callable[[str, str, str], bool]] = None,
) -> None:
    """Register a model adapter.

    Args:
        model_adapter_cls (Type[LLMModelAdapter]): The model adapter class.
        match_funcs (List[Callable[[str, str, str], bool]], optional): The match functions. Defaults to None.
    """
    model_adapters.append(AdapterEntry(model_adapter_cls(), match_funcs))


def get_model_adapter(
        model_type: str,
        model_name: str,
        model_path: str,
) -> Optional[LLMModelAdapter]:
    """Get a model adapter.

    Args:
        model_type (str): The type of the model.
        model_name (str): The name of the model.
        model_path (str): The path of the model.
    Returns:
        Optional[LLMModelAdapter]: The model adapter.
    """
    adapter = None
    # First find adapter by model_name
    for adapter_entry in model_adapters[::-1]:
        if adapter_entry.model_adapter.match(model_type, model_name, None):
            adapter = adapter_entry.model_adapter
            break
    for adapter_entry in model_adapters[::-1]:
        if adapter_entry.model_adapter.match(model_type, None, model_path):
            adapter = adapter_entry.model_adapter
            break
    if adapter:
        new_adapter = adapter.new_adapter()
        new_adapter.model_name = model_name
        new_adapter.model_path = model_path
        return new_adapter
    return None
